#include "common.hpp"

#include <set> 
static const char *optString = "r:h?";

static const struct option longOpts[] = {
	{ "help", no_argument, NULL, 'h' },
	{ "refresh", required_argument, NULL, 'r'},
	{ 0,0,0,0 }
};

int main (int argc, char* const argv[]) {
	// Objetos IPC.
	ipc::semaphore_with_exceptions pantalla_gigante_mostrar ( ftok(BASE_NAME,25),0 );
	ipc::bounded_counter_with_exceptions pantalla_gigante_aviso ( ftok(BASE_NAME,27), ftok(BASE_NAME,26),0 );

	// Parametros.
	long refresco = 30;

	// Variables.
	int longIndex = 0;
	int option = 0;
	bool ayuda = false;

	// Interpretación de parametros.
	while ( (option = getopt_long(argc,argv,optString,longOpts,&longIndex) ) != EOF ) {
		switch (option) {
			case '?':
			case 'h':
			case ':':
				ayuda = true;
				break;
			case 'r':
				refresco = parse<size_t>(optarg,0);
				break;
			default:
				break;
		}
	}

	if ( (ayuda) || (refresco <= 0) ) {
		std::cerr << "Proceso que avisa a la pantalla gigante que se cumplio el tiempo de refresco." << std::endl;
		std::cerr << "\tUso: " << argv[0] << " [-h] <-refresh entero>" << std::endl;
		std::cerr << "\tParametros:" << std::endl;
		std::cerr << "\t\t-h,--help:\tMostrar este mensaje de ayuda." << std::endl;
		std::cerr << "\t\t-r,--refresh:\tCantidad de unidades de tiempo a esperar." << std::endl;
		std::cerr << "\t\tUnidad de tiempo actual = " << SEGUNDO << "us" << std::endl;

		return (ayuda) ? 0 : -1;
	}

//	srand( time(NULL) + getpid() );

	logger.setColor("\033[0;37m");
	refresco*= SEGUNDO; // Para no recalcularlo en cada ciclo.

	// Subproceso encargado de manejar el refresco de la pantalla cada cierto tiempo.
	pantalla_gigante_mostrar.get(PERMITS);
	pantalla_gigante_aviso.get(PERMITS);

	long udelay = 0;
	struct timeval anterior, actual;
	gettimeofday(&anterior,NULL);

	logger << "Pantalla gigante refresco: Inicio. Avisando cada " << refresco << "us." << nl;
	while (true) {
		// Calculo cuanto tiempo del refresco estuve esperando en el wait.
		gettimeofday(&actual,NULL);
		udelay = 1000000*(actual.tv_sec - anterior.tv_sec);
		udelay+= actual.tv_usec - anterior.tv_usec;
		
		if (udelay < refresco) 
			usleep(refresco - udelay);

		pantalla_gigante_aviso.inc();
		// Si se puede incrementar el contador, es que la pantalla está esperando que la despierten.
		if ( pantalla_gigante_aviso.isUltimaOperacionOK() ) {
			logger << "Pantalla gigante refresco: Avisando que se cumplio el tiempo de refresco." << nl;

			pantalla_gigante_mostrar.signal();
		}
		anterior = actual;
	}

	logger << "Pantalla gigante refresco: Fin." << nl;
	return 0;
}

